package cn.iocoder.yudao.module.project.service.internalcode;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.project.controller.admin.workstation.vo.WorkstationRespVO;
import cn.iocoder.yudao.module.project.dal.dataobject.deliveryreceipt.DeliveryReceiptDO;
import cn.iocoder.yudao.module.project.dal.dataobject.deliveryreceiptdetail.DeliveryReceiptDetailDO;
import cn.iocoder.yudao.module.project.dal.dataobject.deptcompletedlog.DeptCompletedLogDO;
import cn.iocoder.yudao.module.project.dal.dataobject.dispatchlist.DispatchListDO;
import cn.iocoder.yudao.module.project.dal.dataobject.electronicscalemanage.ElectronicScaleManageDO;
import cn.iocoder.yudao.module.project.dal.dataobject.order.OrderDO;
import cn.iocoder.yudao.module.project.dal.dataobject.orderdetail.OrderDetailDO;
import cn.iocoder.yudao.module.project.dal.dataobject.productioncode.ProductionCodeDO;
import cn.iocoder.yudao.module.project.dal.dataobject.weighthistory.WeightHistoryDO;
import cn.iocoder.yudao.module.project.dal.dataobject.workstation.WorkstationDO;
import cn.iocoder.yudao.module.project.dal.mysql.deliveryreceipt.DeliveryReceiptMapper;
import cn.iocoder.yudao.module.project.dal.mysql.deliveryreceiptdetail.DeliveryReceiptDetailMapper;
import cn.iocoder.yudao.module.project.dal.mysql.deptcompletedlog.DeptCompletedLogMapper;
import cn.iocoder.yudao.module.project.dal.mysql.dispatchlist.DispatchListMapper;
import cn.iocoder.yudao.module.project.dal.mysql.electronicscalemanage.ElectronicScaleManageMapper;
import cn.iocoder.yudao.module.project.dal.mysql.order.OrderMapper;
import cn.iocoder.yudao.module.project.dal.mysql.orderdetail.OrderDetailMapper;
import cn.iocoder.yudao.module.project.dal.mysql.productioncode.ProductionCodeMapper;
import cn.iocoder.yudao.module.project.dal.mysql.weighthistory.WeightHistoryMapper;
import cn.iocoder.yudao.module.project.dal.mysql.weightthresholdmanage.WeightThresholdManageMapper;
import cn.iocoder.yudao.module.project.dal.mysql.workstation.WorkstationMapper;
import cn.iocoder.yudao.module.project.service.deliveryreceiptdetail.DeliveryReceiptDetailService;
import cn.iocoder.yudao.module.project.service.internalworkstationplan.InternalWorkstationPlanService;
import cn.iocoder.yudao.module.project.service.productprocesscompleted.ProductProcessCompletedService;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

import cn.iocoder.yudao.module.project.controller.admin.internalcode.vo.*;
import cn.iocoder.yudao.module.project.dal.dataobject.internalcode.InternalCodeDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.project.dal.mysql.internalcode.InternalCodeMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.project.config.projectDefine.HTTP_STATUS.*;
import static cn.iocoder.yudao.module.project.config.projectDefine.SERIAL_STR.SERIAL_NUMBER_INIT;
import static cn.iocoder.yudao.module.project.enums.ErrorCodeConstants.*;

/**
 * 内码信息 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
@EnableAspectJAutoProxy(exposeProxy = true)
public class InternalCodeServiceImpl implements InternalCodeService {

    @Resource
    private InternalCodeMapper internalCodeMapper;

    @Resource
    private WeightThresholdManageMapper weightThresholdManageMapper;

    @Resource
    private ElectronicScaleManageMapper electronicScaleManageMapper;

    @Resource
    private WeightHistoryMapper weightHistoryMapper;

    @Resource
    private OrderDetailMapper orderDetailMapper;

    @Resource
    private WorkstationMapper workstationMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private ProductProcessCompletedService productProcessCompletedService;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private PermissionApi permissionApi;

    @Resource
    private DictDataApi dictDataApi;

    @Resource
    private DeptCompletedLogMapper deptCompletedLogMapper;

    @Resource
    private ProductionCodeMapper productionCodeMapper;

    @Resource
    private DispatchListMapper dispatchListMapper;

    @Resource
    private DeliveryReceiptDetailMapper deliveryReceiptDetailMapper;

    @Resource
    private DeliveryReceiptMapper deliveryReceiptMapper;

    @Resource
    private InternalWorkstationPlanService internalWorkstationPlanService;

    @Override
    public String createInternalCode(InternalCodeSaveReqVO createReqVO) {
        // 插入
        InternalCodeDO internalCode = BeanUtils.toBean(createReqVO, InternalCodeDO.class);
        internalCodeMapper.insert(internalCode);

        internalWorkstationPlanService.createInternalWorkstationPlan(internalCode.getId());
        // 返回
        return internalCode.getId();
    }

    @Override
    public void updateInternalCode(InternalCodeSaveReqVO updateReqVO) {
        // 校验存在
        validateInternalCodeExists(updateReqVO.getId());
        // 更新
        InternalCodeDO updateObj = BeanUtils.toBean(updateReqVO, InternalCodeDO.class);
        internalCodeMapper.updateById(updateObj);
    }

    @Override
    public void deleteInternalCode(String id) {
        // 校验存在
        validateInternalCodeExists(id);
        // 删除
        internalCodeMapper.delete(new QueryWrapper<InternalCodeDO>().eq("id", id));
    }

    private void validateInternalCodeExists(String id) {
        if (internalCodeMapper.selectById(id) == null) {
            throw exception(INTERNAL_CODE_NOT_EXISTS);
        }
    }

    @Override
    public InternalCodeDO getInternalCode(String id) {
        return internalCodeMapper.selectById(id);
    }

    @Override
    public PageResult<InternalCodeDO> getInternalCodePage(InternalCodePageReqVO pageReqVO) {
        //internalCodeMapper.selectPage(pageReqVO);
        Page<InternalCodePageReqVO> pageParam = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        List<InternalCodeDO> list = internalCodeMapper.selectInternalCodeByPage(pageParam, pageReqVO);
        PageResult<InternalCodeDO> pageResult = new PageResult<>(list, pageParam.getTotal());
        return pageResult;
    }


    @Override
    public List<InternalCodeDO> selectSavedList(Map<String, Object> params) {
        List<InternalCodeDO> list = internalCodeMapper.selectSavedList(params);
        return list;
    }

    @Override
    @Transactional
    public void insertRecord(List<InternalCodeDO> insertList) {
        // 插入
        if (null != insertList && insertList.size() > 0) {
            // internalCodeMapper.insertList(insertList);
            // 将数据分成2000条一批,分批提交
            List<List<InternalCodeDO>> partition = Lists.partition(insertList, 2000);
            partition.stream().forEach(item -> {
                internalCodeMapper.insertBatch(item);

                ThreadUtil.execute(()->{
                    item.stream().forEach(internalCodeDO -> {
                        internalWorkstationPlanService.createInternalWorkstationPlan(internalCodeDO.getId());
                    });
                });
            });
        }
    }

    @Override
    @Transactional
    //@Async("async")
    public void batchInsertRecord(List<InternalCodeDO> insertList, CountDownLatch countDownLatch) {
        try {
            internalCodeMapper.insertBatch(insertList);

            /*ThreadUtil.execute(() -> {
                for(InternalCodeDO internalCodeDO : insertList){
                    internalWorkstationPlanService.createInternalWorkstationPlan(internalCodeDO.getId());
                }
            });*/

            for(InternalCodeDO internalCodeDO : insertList){
                internalWorkstationPlanService.createInternalWorkstationPlan(internalCodeDO.getId());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            countDownLatch.countDown();
            // log.info("countDownLatch:" + countDownLatch.getCount());
        }
    }

    @Override
    @Transactional
    public void updateRecord(List<InternalCodeDO> updateList) {
        // 更新
        if (null != updateList && updateList.size() > 0) {
            LocalDateTime today = LocalDateTimeUtil.now();
            for (InternalCodeDO data : updateList) {
                data.setUpdateTime(today);
            }

            // internalCodeMapper.updateList(updateList);
            // 将数据分成2000条一批,分批提交
            List<List<InternalCodeDO>> partition = Lists.partition(updateList, 2000);
            partition.stream().forEach(item -> {
                internalCodeMapper.updateBatch(item);
            });
        }
    }

    @Override
    @Async("async")
    public void saveRecord(List<InternalCodeDO> dataList) {
        if (CollectionUtil.isNotEmpty(dataList)) {
            List<String> ids = dataList.stream()
                    .map(c -> {
                        return c.getId();
                    })
                    .distinct()
                    .collect(Collectors.toList());
            Map<String, Object> params = new HashMap<>();
            params.put("ids", ids);

            // 查询已经存在的内码数据,这些将不再写入库中
            List<InternalCodeDO> savedList = this.selectSavedList(params);
            List<InternalCodeDO> updateList = new ArrayList<InternalCodeDO>();
            List<InternalCodeDO> insertList = new ArrayList<InternalCodeDO>();

            for (InternalCodeDO record : dataList) {
                boolean issaved = false;

                if (null != savedList && savedList.size() > 0) {
                    for (InternalCodeDO saved : savedList) {
                        if (
                                saved.getId().equals(record.getId())
                        ) {
                            record.setId(saved.getId());
                            updateList.add(record);
                            issaved = true;
                            break;
                        }
                    }

                }

                if (!issaved) {
                    insertList.add(record);
                }
            }

            // CountDownLatch latch = new CountDownLatch(2);
            // new Thread(() -> {
            //     latch.countDown();
            // }).start();
            // try {
            //     latch.await();
            //     this.insertRecord(insertList);
            //     this.updateRecord(updateList);
            // } catch (InterruptedException e) {
            //     throw new RuntimeException(e);
            // }

            this.insertRecord(insertList);
            this.updateRecord(updateList);
        }
    }

    @Override
    @Async("async")
    public void saveRecordV2(List<InternalCodeDO> dataList) {
        if (CollectionUtil.isNotEmpty(dataList)) {
            long startTime = System.currentTimeMillis();
            this.insertRecord(dataList);
            long endTime = System.currentTimeMillis();
            log.info("总耗时:" + (endTime - startTime));
        }
    }

    @Override
    @Transactional
    public void batchSaveRecord(List<InternalCodeDO> dataList) {
        if (null != dataList && dataList.size() > 0) {
            // 将数据分成2000条一批,分批提交
            List<List<InternalCodeDO>> partition = Lists.partition(dataList, 1000);
            CountDownLatch countDownLatch = new CountDownLatch(partition.size());
            long startTime = System.currentTimeMillis();
            for (List<InternalCodeDO> internalCodeDOS : partition) {
                InternalCodeServiceImpl internalCodeService = (InternalCodeServiceImpl) AopContext.currentProxy();

                // 设置订单详情id
                List<InternalCodeRespVO> internalCodeRespVOS = BeanUtils.toBean(internalCodeDOS, InternalCodeRespVO.class);
                // 下面调用无线

                // 设置规格型号,产品长度,订单类型
                //  internalCodeService.batchSetFlex(internalCodeRespVOS,countDownLatch);
                List<InternalCodeRespVO> internalCodeRespVOSTemp = batchSetFlex(internalCodeRespVOS, countDownLatch);


                List<InternalCodeDO> internalCodeDOSTemp = BeanUtils.toBean(internalCodeRespVOSTemp, InternalCodeDO.class);
                // 批量写入
                internalCodeService.batchInsertRecord(internalCodeDOSTemp,countDownLatch);
                //       internalCodeService.batchInsertRecord(internalCodeDOS,countDownLatch);

            }
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {

            }
            long endTime = System.currentTimeMillis();
            log.info("总耗时:" + (endTime - startTime));
        }
    }

    @Override
    public List<InternalCodeRespVO> updateFlex(List<InternalCodeRespVO> datas) {
        if (CollectionUtil.isEmpty(datas)) {
            return datas;
        }

        String orderCode = datas.get(0).getOrderCode();
        List<OrderDetailDO> orderDetailDOS = orderDetailMapper.selectList(OrderDetailDO::getOrderCode, orderCode);
        // 根据订单详情生成临时流水号
        List<InternalCodeRespVO> internalCodeRespVOS = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(orderDetailDOS)) {
            for (OrderDetailDO orderDetailDO : orderDetailDOS) {
                String flex = orderDetailDO.getFlex();
                Double len = orderDetailDO.getLen();
                Integer num = orderDetailDO.getNum().intValue();

                if (flex.length() >= 6) {
                    String type = flex.substring(0, 6);
                    for (Integer i = 0; i < num; i++) {
                        InternalCodeRespVO internalCodeRespVO = new InternalCodeRespVO();
                        internalCodeRespVO.setOrderCode(orderCode);
                        internalCodeRespVO.setType(type);
                        internalCodeRespVO.setFlex(flex);
                        if (StringUtils.isNotBlank(flex)) {
                            // 对flex进行切割,例如:ST2314芬-95-P28L,切割成[ST2314芬,95,P28L],
                            // 然后将除了最后一个元素的其它元素,与订单的type拼接成字符串,作为flexType
                            String[] flexArr = flex.split("-");
                            String flexStr = String.join("-", Arrays.copyOfRange(flexArr, 0, flexArr.length - 1));
                            // String flexType = String.join("-", flexStr, orderDetailDO.getType(), flexArr[flexArr.length - 1]);
                            String flexType = flexStr + orderDetailDO.getType() + "-" + flexArr[flexArr.length - 1];
                            internalCodeRespVO.setFlexType(flexType);
                        }

                        internalCodeRespVO.setLen(len);
                        internalCodeRespVOS.add(internalCodeRespVO);
                    }
                }
            }
        }

        List<String> typeList = internalCodeRespVOS.stream()
                .map(c -> c.getType())
                .distinct()
                .collect(Collectors.toList());

        for (String type : typeList) {
            Integer startNum = 1;
            for (InternalCodeRespVO internalCodeRespVO : internalCodeRespVOS) {
                if (StringUtils.equals(type, internalCodeRespVO.getType())) {
                    String batchCheckNumber = internalCodeRespVO.getBatchCheckNumber();
                    if (StringUtils.isBlank(batchCheckNumber)) {
                        String serialNumber = SERIAL_NUMBER_INIT + startNum;
                        batchCheckNumber = serialNumber.substring(serialNumber.length() - (SERIAL_NUMBER_INIT.length() + 1));
                        internalCodeRespVO.setBatchCheckNumber(batchCheckNumber);
                        startNum = startNum + 1;
                    }
                }
            }
        }

        // 设置产品规格,长度等信息
        for (InternalCodeRespVO data : datas) {
            for (InternalCodeRespVO internalCodeRespVO : internalCodeRespVOS) {
                if (StringUtils.equals(data.getOrderCode(), internalCodeRespVO.getOrderCode())
                        && StringUtils.equals(data.getType(), internalCodeRespVO.getType())
                        && StringUtils.equals(data.getBatchCheckNumber(), internalCodeRespVO.getBatchCheckNumber())
                ) {
                    String flex = internalCodeRespVO.getFlex();
                    Double len = internalCodeRespVO.getLen();
                    String flexType = internalCodeRespVO.getFlexType();
                    data.setFlex(flex);
                    data.setLen(len);
                    data.setFlexType(flexType);
                }
            }
        }

        return datas;
    }

    @Override
    public void updateOrderDetailId(List<InternalCodeRespVO> dataList) {
        if (CollectionUtil.isEmpty(dataList)) {
            return;
        }

        String orderCode = dataList.get(0).getOrderCode();
        List<OrderDetailDO> orderDetailDOS = orderDetailMapper.selectList("order_code", orderCode);
        if (CollectionUtil.isEmpty(orderDetailDOS)) {
            return;
        }

        for (InternalCodeRespVO data : dataList) {
            for (OrderDetailDO orderDetailDO : orderDetailDOS) {
                if (StringUtils.equals(data.getOrderCode(), orderDetailDO.getOrderCode())
                        && StringUtils.equals(data.getFlex(), orderDetailDO.getFlex())
                ) {
                    data.setOrderDetailId(orderDetailDO.getId());
                }
            }
        }

        List<InternalCodeDO> internalCodeDOS = BeanUtils.toBean(dataList, InternalCodeDO.class);
        this.updateRecord(internalCodeDOS);
    }

    @Override
    public List<InternalCodeRespVO> batchGetInternalCodeList(InternalCodePageReqVO pageReqVO) {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        InternalCodeServiceImpl internalCodeService = (InternalCodeServiceImpl) AopContext.currentProxy();
        List<InternalCodeDO> list = internalCodeService.getInternalCodePage(pageReqVO).getList();
        List<InternalCodeRespVO> datas = BeanUtils.toBean(list, InternalCodeRespVO.class);

        if (null != datas && datas.size() > 0) {
            long startTime = System.currentTimeMillis();
            // 将数据分成2000条一批,分批提交
            List<List<InternalCodeRespVO>> partition = Lists.partition(datas, 2000);
            CountDownLatch countDownLatch = new CountDownLatch(partition.size());
            for (List<InternalCodeRespVO> internalCodeDOS : partition) {
                // 设置规格型号,产品长度,订单类型
                internalCodeService.batchSetFlex(internalCodeDOS, countDownLatch);
            }
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {

            }
            long endTime = System.currentTimeMillis();
            log.info("总耗时:" + (endTime - startTime));
        }

        return datas;
    }

    @Override
    @Async("async")
    public List<InternalCodeRespVO> batchSetFlex(List<InternalCodeRespVO> datas, CountDownLatch countDownLatch) {
        try {
            InternalCodeServiceImpl internalCodeService = (InternalCodeServiceImpl) AopContext.currentProxy();
            // 设置规格型号,产品长度,订单类型
            internalCodeService.updateFlex(datas);

            // 根据订单编号,产品规格,长度等设置订单详情id
            //   internalCodeService.setOrderDetailId(datas);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            countDownLatch.countDown();
            // log.info("countDownLatch:" + countDownLatch.getCount());
            return datas;
        }
    }

    @Override
    public List<InternalCodeRespVO> setOrderDetailId(List<InternalCodeRespVO> datas) {
        if (CollectionUtil.isEmpty(datas)) {
            return datas;
        }

        List<InternalCodeRespVO> collect = datas.stream()
                .filter(c -> StringUtils.isBlank(c.getOrderDetailId()))
                .collect(Collectors.toList());

        if (CollectionUtil.isNotEmpty(collect)) {
            InternalCodeServiceImpl internalCodeService = (InternalCodeServiceImpl) AopContext.currentProxy();
            internalCodeService.updateOrderDetailId(collect);
        }

        return datas;
    }

    @Override
    @Transactional
    public String updateWeight(InternalCodeSaveReqVO updateReqVO) {
        // 校验存在
        validateInternalCodeExists(updateReqVO.getId());


        // 更新
        String id = updateReqVO.getId();
        Double weight = updateReqVO.getWeight();
        String operator = updateReqVO.getOperator();
        String orderCode = updateReqVO.getOrderCode();
        String balanceTwice = updateReqVO.getBalanceTwice();
        Assert.notNull(weight, "重量不能为空");
        // 根据内码id查询产品型号
        InternalCodeDO internalCodeDO = internalCodeMapper.selectById(id);
        String type = internalCodeDO.getType();
        if (StringUtils.isBlank(type)) {
            Assert.notNull(null, "产品型号不能为空");
        }

        // 目前有许多工位都要称重
        Long scaleId = updateReqVO.getScaleId();
        WorkstationDO workstationDO = workstationMapper.selectOne(WorkstationDO::getElectronicScaleId, scaleId);

        if(checkScanWorkstation(id, workstationDO.getId())){
            throw new ServiceException(ERROR_STATUS_EXISTS, "该内码和工位已扫描，请勿重复操作!");
        }

        isNextWorkstation(internalCodeDO.getId(), workstationDO.getId());

        LocalDateTime now = LocalDateTime.now();
        InternalCodeDO updateObj = new InternalCodeDO();
        updateObj.setId(id);
        updateObj.setOrderCode(orderCode);
        updateObj.setWeight(weight);
        updateObj.setOperator(operator);
        updateObj.setOperatingTime(now);
        if (StringUtils.isNotBlank(balanceTwice)) {
            updateObj.setBalanceTwice(balanceTwice);
            updateObj.setBalanceTwiceTime(now);
            if (null == workstationDO) {
                throw exception(new ErrorCode(ERROR_STATUS, "该电子秤未绑定工位"));
            }

            updateObj.setBalanceTwiceWorkstationId(workstationDO.getId());
            updateObj.setBalanceTwiceWorkstationUserId(SecurityFrameworkUtils.getLoginUserId().intValue());
            updateObj.setBalanceTwiceWeight(updateReqVO.getWeight());

            internalCodeMapper.updateById(updateObj);

        }else{
            String internalCode = updateReqVO.getId();
            Integer weightStatus = updateObj.getWeightStatus();
            String nickname = SecurityFrameworkUtils.getLoginUserNickname();

            if (null != scaleId) {
                ElectronicScaleManageDO scaleManageDO = electronicScaleManageMapper.selectOne("id", scaleId);
                if (null == scaleManageDO) {
                    throw new ServiceException(ERROR_STATUS, "电子秤不存在");
                }
                String name = scaleManageDO.getName();
                String ip = scaleManageDO.getIp();
                String port = scaleManageDO.getPort();
                WeightHistoryDO weightHistoryDO = new WeightHistoryDO();
                weightHistoryDO.setOrderCode(internalCodeDO.getOrderCode());
                weightHistoryDO.setInternalCode(internalCode);
                weightHistoryDO.setScaleId(scaleId);
                weightHistoryDO.setWeight(weight);
                weightHistoryDO.setWeightStatus(weightStatus);
                weightHistoryDO.setOperator(nickname);
                weightHistoryDO.setOperatingTime(now);
                weightHistoryDO.setIp(ip);
                weightHistoryDO.setPort(port);
                weightHistoryDO.setScaleName(name);
                weightHistoryDO.setId(internalCode + "_" + scaleId);

                if (StringUtils.isBlank(balanceTwice)) {

                    if (null == workstationDO) {
                        throw exception(new ErrorCode(ERROR_STATUS, "该电子秤未绑定工位"));
                    }

                    weightHistoryDO.setWeightWorkstationId(workstationDO.getId());
                    weightHistoryDO.setWeightWorkstationUserId(SecurityFrameworkUtils.getLoginUserId().intValue());
                }

                WeightHistoryDO existWeightHistory = weightHistoryMapper.selectOne("id", internalCode + "_" + scaleId);
                if (null != existWeightHistory) {
                    weightHistoryMapper.updateById(weightHistoryDO);
                }
                if (null == existWeightHistory) {
                    weightHistoryMapper.insert(weightHistoryDO);
                }
            }
        }

        productProcessCompletedService.createProductProcessCompleted(internalCodeDO.getId(), workstationDO.getId());

        return "称重成功";
    }

    @Override
    public void updateRigidity(InternalCodeSaveReqVO updateReqVO) {
        // 校验存在
        validateInternalCodeExists(updateReqVO.getId());
        // 更新
        String id = updateReqVO.getId();
        LocalDateTime now = LocalDateTime.now();
        String rigidity = updateReqVO.getRigidity();
        Assert.notNull(rigidity, "刚性测试结果不能为空");

        InternalCodeDO updateObj = new InternalCodeDO();
        updateObj.setId(id);
        updateObj.setRigidity(rigidity);
        updateObj.setRigidityTime(now);
        updateObj.setTestWorkstationId(updateReqVO.getTestWorkstationId());
        updateObj.setTestWorkstationUserId(updateReqVO.getTestWorkstationUserId());

        internalCodeMapper.updateById(updateObj);
    }

    @Override
    public void updateBalance(InternalCodeSaveReqVO updateReqVO) {
        // 校验存在
        validateInternalCodeExists(updateReqVO.getId());
        // 更新
        String id = updateReqVO.getId();
        LocalDateTime now = LocalDateTime.now();
        String balance = updateReqVO.getBalance();
        Assert.notNull(balance, "平衡测试结果不能为空");

        InternalCodeDO updateObj = new InternalCodeDO();
        updateObj.setId(id);
        updateObj.setBalance(balance);
        updateObj.setBalanceTime(now);
        updateObj.setTestWorkstationId(updateReqVO.getTestWorkstationId());
        updateObj.setTestWorkstationUserId(updateReqVO.getTestWorkstationUserId());
        updateObj.setTestWeight(updateReqVO.getWeight());

        internalCodeMapper.updateById(updateObj);
    }

    public boolean isContinuous(Integer[] nums) {
        if (nums == null || nums.length <= 1) {
            return true;
        }

        // 先对数组排序
        Arrays.sort(nums, Comparator.reverseOrder());

        // 检查相邻元素是否差1
        for (int i = 0; i < nums.length - 1; i++) {
            if (nums[i].intValue() - nums[i + 1].intValue() != 1 && nums[i].intValue() - nums[i + 1].intValue() != 0) {
                return false;
            }
        }

        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void clearWeightHistory(Map<String, Object> params) {
        String internalCode = (String) params.get("internalCode");
        String workstationIdListStr = (String)params.get("workstationIdList");

        String[] workstationIdArray = workstationIdListStr.split(",");
        List<Integer> workstationIdIntList = new ArrayList<>();
        for(int i = 0; i < workstationIdArray.length; i++){
            workstationIdIntList.add(Integer.parseInt(workstationIdArray[i]));
        }

        List<WorkstationDO> workstationList = workstationMapper.selectList(new QueryWrapper<WorkstationDO>().in("id", workstationIdIntList));
        List<Integer> processOrderList = workstationList.stream().map(item -> item.getProcessOrder()).collect(Collectors.toList());

        Integer[] processOrderArray = processOrderList.toArray(new Integer[0]);

        if(!isContinuous(processOrderArray)){
            throw new ServiceException(ERROR_STATUS, "请选择连续的工位!");
        }

        List<Integer> workstationIdIntArray = workstationList.stream().sorted((o1, o2) -> o2.getProcessOrder() - o1.getProcessOrder()).map(item -> item.getId()).collect(Collectors.toList());

        for(Integer workstationId : workstationIdIntArray){

            WorkstationDO currentWorkstationDO = workstationMapper.selectById(workstationId);
            Integer currProcessOrder = currentWorkstationDO.getProcessOrder();

            List<Integer> workstationIdList = new ArrayList<>();

            InternalCodeDO internalCodeDO = internalCodeMapper.selectById(internalCode);
            Integer testWorkstationId = internalCodeDO.getTestWorkstationId();
            Integer balanceTwiceWorkstationId = internalCodeDO.getBalanceTwiceWorkstationId();

            if(null != testWorkstationId){
                workstationIdList.add(testWorkstationId);
            }
            if(null != balanceTwiceWorkstationId){
                workstationIdList.add(balanceTwiceWorkstationId);
            }

            List<WeightHistoryDO> weightHistoryDOList = weightHistoryMapper.selectList("internal_code", internalCode);
            if(null != weightHistoryDOList && weightHistoryDOList.size() > 0){
                for (WeightHistoryDO weightHistoryDO : weightHistoryDOList) {
                    if(null != weightHistoryDO.getWeightWorkstationId()){
                        workstationIdList.add(weightHistoryDO.getWeightWorkstationId());
                    }
                }
            }

            List<ProductionCodeDO> productionCodeDOList = productionCodeMapper.selectList(ProductionCodeDO::getInternalCode, internalCode);
            if(null != productionCodeDOList && productionCodeDOList.size() > 0){
                for (ProductionCodeDO productionCodeDO : productionCodeDOList){
                    if(null != productionCodeDO.getAssociatedWorkstationId()){
                        workstationIdList.add(productionCodeDO.getAssociatedWorkstationId());
                    }
                }
            }


            if(null != workstationIdList && workstationIdList.size() > 0){
                List<WorkstationDO> workstationDOList = workstationMapper.selectList(new QueryWrapper<WorkstationDO>().in("id", workstationIdList).eq("is_control", 1));
                WorkstationDO maxWorkstationDO = workstationDOList.stream().max(Comparator.comparingInt(WorkstationDO::getProcessOrder)).get();
                Integer maxProcessOrder = maxWorkstationDO.getProcessOrder();

                String workstationName = maxWorkstationDO.getWorkstationName();

                if(currProcessOrder.intValue() != maxProcessOrder.intValue()){
                    throw new ServiceException(ERROR_STATUS, "请按先处理"+workstationName+"工位数据!");
                }
            }

            InternalCodeDO updateInnernalCodeDO = new InternalCodeDO();
            updateInnernalCodeDO.setId(internalCode);

            QueryWrapper<InternalCodeDO> innernalCodeQueryWrapper = new QueryWrapper<InternalCodeDO>();
            innernalCodeQueryWrapper.eq("id", internalCode);

            UpdateWrapper<InternalCodeDO> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", internalCode);

            if (null != testWorkstationId && workstationId.equals(testWorkstationId)) {
                updateWrapper.set("weight", null);
                updateWrapper.set("rigidity", null);
                updateWrapper.set("rigidity_status", null);
                updateWrapper.set("rigidity_time", null);
                updateWrapper.set("balance", null);
                updateWrapper.set("balance_status", null);
                updateWrapper.set("balance_time", null);
                updateWrapper.set("test_workstation_id", null);
                updateWrapper.set("test_workstation_user_id", null);
                updateWrapper.set("test_weight", null);
            }

            if (null != balanceTwiceWorkstationId && workstationId.equals(balanceTwiceWorkstationId)) {
                updateWrapper.set("balance_twice_time", null);
                updateWrapper.set("balance_twice", null);
                updateWrapper.set("balance_twice_workstation_id", null);
                updateWrapper.set("balance_twice_workstation_user_id", null);
                updateWrapper.set("balance_twice_weight", null);
            }
            internalCodeMapper.update(updateInnernalCodeDO, updateWrapper);


            QueryWrapper<WeightHistoryDO> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("internal_code", internalCode)
                    .eq("weight_workstation_id", workstationId);
            weightHistoryMapper.delete(queryWrapper);


            if(null != productionCodeDOList && productionCodeDOList.size() > 0){
                productionCodeMapper.delete(new QueryWrapper<ProductionCodeDO>().eq("internal_code", internalCode).eq("associated_workstation_id", workstationId));
            }

            Integer department = currentWorkstationDO.getDepartment();

            productProcessCompletedService.deleteProductProcessCompletedByInternalCode(internalCode, department);


            DeliveryReceiptDetailDO deliveryReceiptDetailDO = deliveryReceiptDetailMapper.selectOne(new QueryWrapper<DeliveryReceiptDetailDO>().eq("internal_code", internalCode).eq("out_dept_id",  department));

            if(null != deliveryReceiptDetailDO){
                Integer deliveryReceiptId = deliveryReceiptDetailDO.getDeliveryReceiptId();

                deliveryReceiptDetailMapper.deleteById(deliveryReceiptDetailDO.getId());

                DeliveryReceiptDO deliveryReceipt = deliveryReceiptMapper.selectById(deliveryReceiptId);

                if(null != deliveryReceipt){
                    Integer deliveryCount = deliveryReceipt.getDeliveryCount();
                    if(deliveryCount.intValue() == 0){
                        deliveryReceiptMapper.deleteById(deliveryReceiptId);
                    }else{
                        deliveryReceipt.setDeliveryCount(deliveryCount - 1);
                        deliveryReceiptMapper.updateById(deliveryReceipt);
                    }
                }
            }

        }

        //internalCodeMapper.clearWeightHistory(params);
        //weightHistoryMapper.clearWeightHistory(params);
    }

    @Override
    public List<WorkstationRespVO> getWorkstationFromInternalCode(String code) {
        List<WorkstationRespVO> workstationRespVOList = new ArrayList<>();

        InternalCodeDO internalCodeDO = internalCodeMapper.selectById(code);

        List<WeightHistoryDO> weightHistoryDOList = weightHistoryMapper.selectList(WeightHistoryDO::getInternalCode, internalCodeDO.getId());

        List<Integer> workstationIdList = new ArrayList<>();
        Integer testWorkstationId = internalCodeDO.getTestWorkstationId();
        if (null != testWorkstationId) {
            workstationIdList.add(testWorkstationId);
        }
        Integer balanceTwiceWorkstationId = internalCodeDO.getBalanceTwiceWorkstationId();
        if (null != balanceTwiceWorkstationId) {
            workstationIdList.add(balanceTwiceWorkstationId);
        }
        for (WeightHistoryDO weightHistoryDO : weightHistoryDOList) {
            Integer workstationId = weightHistoryDO.getWeightWorkstationId();
            if (null != workstationId) {
                workstationIdList.add(workstationId);
            }
        }

        List<ProductionCodeDO> productionCodeDOList = productionCodeMapper.selectList(ProductionCodeDO::getInternalCode, internalCodeDO.getId());
        if(null != productionCodeDOList && productionCodeDOList.size() > 0){
            for (ProductionCodeDO productionCodeDO : productionCodeDOList){
                if(null != productionCodeDO.getAssociatedWorkstationId()){
                    workstationIdList.add(productionCodeDO.getAssociatedWorkstationId());
                }
            }
        }

        if (workstationIdList.size() > 0) {
            QueryWrapper<WorkstationDO> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("id", workstationIdList);
            queryWrapper.orderByDesc("process_order");
            List<WorkstationDO> workstationDOList = workstationMapper.selectList(queryWrapper);
            for (WorkstationDO workstationDO : workstationDOList) {
                WorkstationRespVO workstationRespVO = BeanUtils.toBean(workstationDO, WorkstationRespVO.class);
                workstationRespVOList.add(workstationRespVO);
            }
        }

        return workstationRespVOList;
    }

    @Override
    public PageResult<InternalCodeWorkstationRespVO> listWorkstationDetail(InternalCodePageReqVO pageReqVO) {
        Long loginUserId = WebFrameworkUtils.getLoginUserId();

        String labelType = pageReqVO.getLabelType();
        Long labelTypeValue = pageReqVO.getLabelTypeValue();


        if(null != pageReqVO.getOperatorTimeReq() && pageReqVO.getOperatorTimeReq().length > 0){
            String[] operatorTimeArr = pageReqVO.getOperatorTimeReq();
            pageReqVO.setStartTime(operatorTimeArr[0]);
            pageReqVO.setEndTime(operatorTimeArr[1]);
        }

        boolean commonFlag = permissionApi.hasAnyRoles(loginUserId, "longyi_common");
        boolean adminFlag = permissionApi.hasAnyRoles(loginUserId, "longyi_admin");
        boolean managerFlag = permissionApi.hasAnyRoles(loginUserId, "longyi_manager");

        InternalCodeRoleVO internalCodeRoleVO = new InternalCodeRoleVO();

        if(adminFlag){

        }else if (managerFlag){
            internalCodeRoleVO.setRole("manager");

            AdminUserRespDTO adminUserRespDTO = adminUserApi.getUser(loginUserId);
            Long deptId = adminUserRespDTO.getDeptId();
            List<WorkstationDO> workstationDOList = workstationMapper.selectList(WorkstationDO::getDepartment, deptId);
            List<Integer> workstationIdList = workstationDOList.stream().map(workstationDO -> workstationDO.getId()).collect(Collectors.toList());

            String workstationIdListStr = workstationIdList.stream().map(workstationId -> workstationId.toString()).collect(Collectors.joining(","));
            internalCodeRoleVO.setWorkstationIdList(workstationIdListStr);

        }else if(commonFlag){
            internalCodeRoleVO.setRole("common");
            internalCodeRoleVO.setUserId(loginUserId.toString());

            List<WorkstationDO> workstationDOList = workstationMapper.selectList(WorkstationDO::getUserId, loginUserId);
            List<Integer> workstationIdList = workstationDOList.stream().map(workstationDO -> workstationDO.getId()).collect(Collectors.toList());

            String workstationIdListStr = workstationIdList.stream().map(workstationId -> workstationId.toString()).collect(Collectors.joining(","));
            internalCodeRoleVO.setWorkstationIdList(workstationIdListStr);
        }

        String orderCode = null;
        if(!"report".equals(pageReqVO.getChannel())){

            if(loginUserId == null){
                throw new ServiceException(ERROR_STATUS_LOGOUT, "登录信息已失效，请重新登录。");
            }

            Object orderCodeObj = stringRedisTemplate.opsForHash().get("CACHE_ORDER_CODE", String.valueOf(loginUserId));
            if(null != orderCodeObj){
                orderCode = orderCodeObj.toString();
            }
            if(null != orderCode){
                pageReqVO.setOrderCode(orderCode);
            }

            if(!ObjectUtils.isEmpty(pageReqVO.getCacheOrderCode())){
                if(!"undefined".equalsIgnoreCase(pageReqVO.getCacheOrderCode()) && !"null".equalsIgnoreCase(pageReqVO.getCacheOrderCode())){
                    pageReqVO.setOrderCode(pageReqVO.getCacheOrderCode());
                }
            }else{
                if(null == orderCode){
                    pageReqVO.setOrderCode(getFirstCacheOrderCode());
                }
            }

            if(!ObjectUtils.isEmpty(labelTypeValue)){
                if("dept".equals(labelType)){
                    List<WorkstationDO> workstationDOList = workstationMapper.selectList(WorkstationDO::getDepartment, labelTypeValue);
                    List<Integer> workstationIdList = workstationDOList.stream().map(workstationDO -> workstationDO.getId()).collect(Collectors.toList());
                    String workstationIdListStr = workstationIdList.stream().map(workstationId -> workstationId.toString()).collect(Collectors.joining(","));
                    internalCodeRoleVO.setWorkstationIdList(workstationIdListStr);
                }else if("workstation".equals(labelType)){
                    pageReqVO.setWorkstationId(labelTypeValue.intValue());
                }
            }
        }

        Page<InternalCodeWorkstationRespVO> pageParam = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        List<InternalCodeWorkstationRespVO> list = null;
        if(!ObjectUtils.isEmpty(pageReqVO.getFinishStatus())){
            list = internalCodeMapper.listUnfinishReport(pageParam, pageReqVO, internalCodeRoleVO);
        }else{
            list = internalCodeMapper.listWorkstationDetail(pageParam, pageReqVO, internalCodeRoleVO);
        }

        PageResult<InternalCodeWorkstationRespVO> pageResult = new PageResult<>(list, pageParam.getTotal());
        return pageResult;
    }

    private String getFirstCacheOrderCode(){
        Set set = listCacheOrder();
        List cacheOrderCodeList = new ArrayList<>();
        cacheOrderCodeList.addAll(set);
        return cacheOrderCodeList.get(0).toString();
    }

    private Long getUnfinishCount(InternalCodePageReqVO pageReqVO, String orderCode, Long loginUserId){

        boolean commonFlag = permissionApi.hasAnyRoles(loginUserId, "longyi_common");
        boolean adminFlag = permissionApi.hasAnyRoles(loginUserId, "longyi_admin");
        boolean managerFlag = permissionApi.hasAnyRoles(loginUserId, "longyi_manager");

        InternalCodeRoleVO internalCodeRoleVO = new InternalCodeRoleVO();

        if(adminFlag){

        }else if (managerFlag){
            internalCodeRoleVO.setRole("manager");

            AdminUserRespDTO adminUserRespDTO = adminUserApi.getUser(loginUserId);
            Long deptId = adminUserRespDTO.getDeptId();
            List<WorkstationDO> workstationDOList = workstationMapper.selectList(WorkstationDO::getDepartment, deptId);
            List<Integer> workstationIdList = workstationDOList.stream().map(workstationDO -> workstationDO.getId()).collect(Collectors.toList());

            String workstationIdListStr = workstationIdList.stream().map(workstationId -> workstationId.toString()).collect(Collectors.joining(","));
            internalCodeRoleVO.setWorkstationIdList(workstationIdListStr);

        }else if(commonFlag){
            internalCodeRoleVO.setRole("common");
            internalCodeRoleVO.setUserId(loginUserId.toString());

            List<WorkstationDO> workstationDOList = workstationMapper.selectList(WorkstationDO::getUserId, loginUserId);
            List<Integer> workstationIdList = workstationDOList.stream().map(workstationDO -> workstationDO.getId()).collect(Collectors.toList());

            String workstationIdListStr = workstationIdList.stream().map(workstationId -> workstationId.toString()).collect(Collectors.joining(","));
            internalCodeRoleVO.setWorkstationIdList(workstationIdListStr);
        }

        pageReqVO.setOrderCode(orderCode);
        Long count = internalCodeMapper.getUnfinishCount(pageReqVO, internalCodeRoleVO);
        return count;
    }

    @Override
    public List<Map<String, Object>> listCurrentUserWorkstationOrderInfo(Integer deptId, String cacheOrderCode, Long loginUserId) {
        if("undefined".equalsIgnoreCase(cacheOrderCode) || "null".equalsIgnoreCase(cacheOrderCode)){
            cacheOrderCode = null;
        }
        List<Map<String, Object>> list = new ArrayList<>();

        if(loginUserId == null){
            throw new ServiceException(ERROR_STATUS_LOGOUT, "登录信息已失效，请重新登录。");
        }

        //Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        Object orderCodeObj = stringRedisTemplate.opsForHash().get("CACHE_ORDER_CODE", String.valueOf(loginUserId));
        String orderCode = null;
        if(null != orderCodeObj){
            orderCode = orderCodeObj.toString();
        }

        if(!ObjectUtils.isEmpty(cacheOrderCode)){
            orderCode = cacheOrderCode;
        }

        if(ObjectUtils.isEmpty(orderCode) && ObjectUtils.isEmpty(orderCodeObj)){
            //orderCode = getFirstCacheOrderCode();
            throw new ServiceException(ERROR_STATUS, "未获取到订单信息");
        }

        /**
         * 1. 工位上的用户只能看到自己工位上的数据，首页显示：总数，未完成数，工位已完成数据
         * 2. 每个课室的主管，可以看到自己课室每个工位上的数据，首页显示：总数，未完成数，本课室所有工位已完成数据
         * 3. 超级管理员，可以看到所有课室的数据，首页显示：总数，未完成数，A，B，C课已完成数据。
         */

        boolean commonFlag = permissionApi.hasAnyRoles(loginUserId, "longyi_common");
        boolean adminFlag = permissionApi.hasAnyRoles(loginUserId, "longyi_admin");
        boolean managerFlag = permissionApi.hasAnyRoles(loginUserId, "longyi_manager");

        OrderDO order = orderMapper.selectById(orderCode);

        Map<String, Object> totalMap = new HashMap<>();
        totalMap.put("label", "总数");

        Long totalNum = 0L;
        if(null != order){
            totalNum = order.getTotalNum();
        }else{
            List<DispatchListDO> dispatchListDOList = dispatchListMapper.selectList(DispatchListDO::getTicketNumber, orderCode);
            if(null != dispatchListDOList && dispatchListDOList.size() > 0){
                totalNum = dispatchListDOList.stream().mapToLong(dispatchListDO -> Long.valueOf(dispatchListDO.getQuantity().intValue())).sum();
            }
        }
        totalMap.put("value", totalNum);
        list.add(totalMap);


        Map<String, Object> unfinishedMap = new HashMap<>();

        QueryWrapper<DeptCompletedLogDO> deptCompletedLogDOQueryWrapper = new QueryWrapper<>();
        deptCompletedLogDOQueryWrapper.eq("dept_id", deptId);
        deptCompletedLogDOQueryWrapper.eq("order_code", orderCode);
        Long deptFinishedCount = 0L; //deptCompletedLogMapper.selectCount(deptCompletedLogDOQueryWrapper);
        //Long deptUnfinishedCount = totalNum - deptFinishedCount;
        unfinishedMap.put("label", "未完成");
        //unfinishedMap.put("value", deptUnfinishedCount);

        InternalCodePageReqVO pageReqVO = new InternalCodePageReqVO();
        Long unfinishCount = getUnfinishCount(pageReqVO, orderCode, loginUserId);
        unfinishedMap.put("value", unfinishCount);

        list.add(unfinishedMap);

        if(adminFlag){

            Long deptCFinishCount = 0L;

            List<DictDataRespDTO> dictDataRespDTOList = dictDataApi.getDictDataList("workstation_dept");
            for(DictDataRespDTO dictDataRespDTO : dictDataRespDTOList){
                if(dictDataRespDTO.getLabel().contains("A课") || dictDataRespDTO.getLabel().contains("B课") || dictDataRespDTO.getLabel().contains("C课")){
                    deptCompletedLogDOQueryWrapper = new QueryWrapper<>();
                    deptCompletedLogDOQueryWrapper.eq("dept_id", dictDataRespDTO.getValue());
                    deptCompletedLogDOQueryWrapper.eq("order_code", orderCode);
                    deptFinishedCount = deptCompletedLogMapper.selectCount(deptCompletedLogDOQueryWrapper);

                    if(dictDataRespDTO.getLabel().contains("C课")){
                        deptCFinishCount = deptFinishedCount;
                    }

                    Map<String, Object> deptFinishMap = new HashMap<>();
                    deptFinishMap.put("label", dictDataRespDTO.getLabel());
                    deptFinishMap.put("value", deptFinishedCount);
                    deptFinishMap.put("labelType", "dept");
                    deptFinishMap.put("labelTypeValue", dictDataRespDTO.getValue());
                    list.add(deptFinishMap);
                }
            }

            //Long unfinishCount = Long.parseLong(unfinishedMap.get("value").toString()) - deptCFinishCount;
            //unfinishedMap.put("value", unfinishCount);

        }else if(managerFlag){
            List<WorkstationDO> workstationDOList = workstationMapper.selectList(WorkstationDO::getDepartment, deptId);
            if (!ObjectUtils.isEmpty(workstationDOList)) {
                for (WorkstationDO workstationDO : workstationDOList) {
                    Map<String, Object> workstationMap = new HashMap<>();

                    Integer workstationId = workstationDO.getId();
                    String workstationName = workstationDO.getWorkstationName();

                    QueryWrapper<InternalCodeDO> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("order_code", orderCode);
                    queryWrapper.and(qw -> qw.eq("test_workstation_id", workstationId).or().eq("balance_twice_workstation_id", workstationId));

                    Long internalWorkstationFinishedNum = internalCodeMapper.selectCount(queryWrapper);

                    Long workstationFinishedNum = internalWorkstationFinishedNum;

                    QueryWrapper<WeightHistoryDO> weightHistoryQueryWrapper = new QueryWrapper<>();
                    weightHistoryQueryWrapper.eq("weight_workstation_id", workstationId);
                    weightHistoryQueryWrapper.eq("order_code", orderCode);

                    Long weightWorkstationFinishedNum = weightHistoryMapper.selectCount(weightHistoryQueryWrapper);
                    workstationFinishedNum = workstationFinishedNum + weightWorkstationFinishedNum;

                    QueryWrapper<ProductionCodeDO> productionCodeDOQueryWrapper = new QueryWrapper<>();
                    productionCodeDOQueryWrapper.eq("associated_workstation_id", workstationId);
                    productionCodeDOQueryWrapper.eq("order_code", orderCode);
                    Long productionCodeFinishedNum = productionCodeMapper.selectCount(productionCodeDOQueryWrapper);
                    workstationFinishedNum = workstationFinishedNum + productionCodeFinishedNum;

                    workstationMap.put("label", workstationName);
                    workstationMap.put("value", workstationFinishedNum);
                    workstationMap.put("labelType", "workstation");
                    workstationMap.put("labelTypeValue", workstationId);
                    list.add(workstationMap);

                }
            }
        }else if(commonFlag){

            Map<String, Object> workstationMap = new HashMap<>();

            QueryWrapper<InternalCodeDO> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("order_code", orderCode);
            queryWrapper.and(qw -> qw.eq("test_workstation_user_id", loginUserId).or().eq("balance_twice_workstation_user_id", loginUserId));

            Long internalWorkstationFinishedNum = internalCodeMapper.selectCount(queryWrapper);
            Long workstationFinishedNum = internalWorkstationFinishedNum;

            String workstationName = null;
            Integer workstationId = null;

            QueryWrapper<InternalCodeDO> testWorkstationQueryWrapper = new QueryWrapper<>();
            testWorkstationQueryWrapper.eq("order_code", orderCode);
            testWorkstationQueryWrapper.eq("test_workstation_user_id", loginUserId);
            testWorkstationQueryWrapper.last(" limit 1");

            InternalCodeDO internalCodeDO = internalCodeMapper.selectOne(testWorkstationQueryWrapper);

            if(null != internalCodeDO){
                workstationId = internalCodeDO.getTestWorkstationId();
                workstationName = getWorkstationName(workstationId);
            }

            if(null == workstationName){
                testWorkstationQueryWrapper = new QueryWrapper<>();
                testWorkstationQueryWrapper.eq("order_code", orderCode);
                testWorkstationQueryWrapper.eq("balance_twice_workstation_user_id", loginUserId);
                testWorkstationQueryWrapper.last(" limit 1 ");

                internalCodeDO = internalCodeMapper.selectOne(testWorkstationQueryWrapper);

                if(null != internalCodeDO){
                    workstationId = internalCodeDO.getBalanceTwiceWorkstationId();
                    workstationName = getWorkstationName(workstationId);
                }

            }

            QueryWrapper<WeightHistoryDO> weightHistoryQueryWrapper = new QueryWrapper<>();
            weightHistoryQueryWrapper.eq("weight_workstation_user_id", loginUserId);
            weightHistoryQueryWrapper.eq("order_code", orderCode);
            Long weightWorkstationFinishedNum = weightHistoryMapper.selectCount(weightHistoryQueryWrapper);
            workstationFinishedNum = workstationFinishedNum + weightWorkstationFinishedNum;


            if(null == workstationName){
                QueryWrapper<WeightHistoryDO> weightHistoryDOQueryWrapper = new QueryWrapper<>();
                weightHistoryDOQueryWrapper.eq("order_code", orderCode);
                weightHistoryDOQueryWrapper.eq("weight_workstation_user_id", loginUserId);
                weightHistoryDOQueryWrapper.last(" limit 1 ");

                WeightHistoryDO weightHistoryDO = weightHistoryMapper.selectOne(weightHistoryDOQueryWrapper);
                if(null != weightHistoryDO){
                    workstationId = weightHistoryDO.getWeightWorkstationId();
                    workstationName = getWorkstationName(workstationId);
                }

            }

            QueryWrapper<ProductionCodeDO> productionCodeWrapper = new QueryWrapper<>();
            productionCodeWrapper.eq("associated_workstation_user_id", loginUserId);
            productionCodeWrapper.eq("order_code", orderCode);
            Long productWorkstationFinishedNum = productionCodeMapper.selectCount(productionCodeWrapper);
            workstationFinishedNum = workstationFinishedNum + productWorkstationFinishedNum;


            if(null == workstationName){
                QueryWrapper<ProductionCodeDO> productionCodeDOQueryWrapper = new QueryWrapper<>();
                productionCodeDOQueryWrapper.eq("order_code", orderCode);
                productionCodeDOQueryWrapper.eq("associated_workstation_user_id", loginUserId);
                productionCodeDOQueryWrapper.last(" limit 1 ");

                ProductionCodeDO productionCodeDO = productionCodeMapper.selectOne(productionCodeDOQueryWrapper);
                if(null != productionCodeDO){
                    workstationId = productionCodeDO.getAssociatedWorkstationId();
                    workstationName = getWorkstationName(workstationId);
                }

            }

            if(null != workstationName){
                workstationMap.put("label", workstationName);
                workstationMap.put("value", workstationFinishedNum);
                workstationMap.put("labelType", "workstation");
                workstationMap.put("labelTypeValue", workstationId);

                list.add(workstationMap);

                //unfinishedMap.put("value", totalNum - workstationFinishedNum);
            }
        }

        return list;
    }

    public String getWorkstationName(Integer workstationId){
        if(null != workstationId){
            WorkstationDO workstationDO = workstationMapper.selectById(workstationId);
            if(null != workstationDO){
                return workstationDO.getWorkstationName();
            }
        }
        return null;
    }

    public boolean isNextWorkstation(String internalCode, Integer workstationId) {

        WorkstationDO currWorkstationDO = workstationMapper.selectById(workstationId);
        Integer currProcessOrder = currWorkstationDO.getProcessOrder();


        List<WorkstationDO> workstationDOList = workstationMapper.selectList(new QueryWrapper<WorkstationDO>().eq("is_control", 1).orderByAsc("process_order"));

        List<Integer> workstationIdList = new ArrayList<>();

        InternalCodeDO internalCodeDO = internalCodeMapper.selectById(internalCode);
        if (null != internalCodeDO) {
            Integer testWorkstationId = internalCodeDO.getTestWorkstationId();
            if (null != testWorkstationId) {
                workstationIdList.add(testWorkstationId);
            }
            Integer balanceTwiceWorkstationId = internalCodeDO.getBalanceTwiceWorkstationId();
            if (null != balanceTwiceWorkstationId) {
                workstationIdList.add(balanceTwiceWorkstationId);
            }
        }

        List<WeightHistoryDO> weightHistoryDOList = weightHistoryMapper.selectList(WeightHistoryDO::getInternalCode, internalCode);
        if(!ObjectUtils.isEmpty(weightHistoryDOList)){
            for (WeightHistoryDO weightHistoryDO : weightHistoryDOList) {
                Integer weightWorkstationId = weightHistoryDO.getWeightWorkstationId();
                if (null != weightWorkstationId) {
                    workstationIdList.add(weightWorkstationId);
                }
            }
        }

        List<ProductionCodeDO> productionCodeDOList = productionCodeMapper.selectList(ProductionCodeDO::getInternalCode, internalCode);
        if(null != productionCodeDOList && productionCodeDOList.size() > 0){
            for (ProductionCodeDO productionCodeDO : productionCodeDOList){
                if(null != productionCodeDO.getAssociatedWorkstationId()){
                    workstationIdList.add(productionCodeDO.getAssociatedWorkstationId());
                }
            }
        }

        if(ObjectUtils.isEmpty(workstationIdList)){
            Integer firstProcessOrder = workstationDOList.get(0).getProcessOrder();
            if(firstProcessOrder.intValue() == currProcessOrder.intValue()){
                return true;
            }

            throw exception(new ErrorCode(ERROR_STATUS, "请选择" + workstationDOList.get(0).getWorkstationName()+"工位!"));
        }

        List<WorkstationDO> sortedWorkstationDOList = workstationMapper.selectList(new QueryWrapper<WorkstationDO>().in("id", workstationIdList).eq("is_control", 1).orderByAsc("process_order"));

        WorkstationDO maxWorkstationDO = sortedWorkstationDOList.stream().max(Comparator.comparing(WorkstationDO::getProcessOrder)).get();
        Integer maxProcessOrder = maxWorkstationDO.getProcessOrder();

        if(currProcessOrder.intValue() == maxProcessOrder.intValue() + 1){
            Integer currDeptId = currWorkstationDO.getDepartment();
            DictDataRespDTO dictDataRespDTO = dictDataApi.getDictData("workstation_dept", String.valueOf(currDeptId));
            String currDeptName = dictDataRespDTO.getLabel();
            if("B课".equals(currDeptName)){
                validateSubmitDeliveryReceipt("A课", internalCodeDO.getOrderCode(), internalCode);
            }else if("C课".equals(currDeptName)){
                validateSubmitDeliveryReceipt("B课", internalCodeDO.getOrderCode(), internalCode);
            }
            return true;
        }

        List<WorkstationDO> nextWorkstationDOList = workstationMapper.selectList(WorkstationDO::getProcessOrder, maxProcessOrder.intValue() + 1);
        if(null != nextWorkstationDOList && nextWorkstationDOList.size() > 0){
            WorkstationDO nextWorkstation = nextWorkstationDOList.get(0);
            throw exception(new ErrorCode(ERROR_STATUS, "请选择"+nextWorkstation.getWorkstationName()+"工位!"));
        }
        return true;
    }

    @Override
    @Transactional
    public void rigidityAndBalance(InternalCodeSaveReqVO updateReqVO) {
        String id = updateReqVO.getId();
        if (StringUtils.isBlank(id)) {
            throw new ServiceException(ERROR_STATUS, "请输入内码");
        }

        Long scaleId = updateReqVO.getScaleId();
        ElectronicScaleManageDO scaleManageDO = electronicScaleManageMapper.selectOne("id", scaleId);
        if (null == scaleManageDO) {
            throw new ServiceException(ERROR_STATUS, "电子秤不存在");
        }

        InternalCodeDO internalCodeDO = internalCodeMapper.selectById(id);
        if (null != internalCodeDO) {

            String rigidity = internalCodeDO.getRigidity();
            if (StringUtils.isNotBlank(rigidity)) {
                throw new ServiceException(ERROR_STATUS_EXISTS, "该内码" + id + "已经执行了刚性测试");
            }
            String balance = internalCodeDO.getBalance();
            if (StringUtils.isNotBlank(balance)) {
                throw new ServiceException(ERROR_STATUS_EXISTS, "该内码" + id + "已经执行了平衡测试");
            }
        }

        WorkstationDO workstationDO = workstationMapper.selectOne(new QueryWrapper<WorkstationDO>().eq("electronic_scale_id", updateReqVO.getScaleId()).last(" limit 1 "));
        Integer testWorkstationId = workstationDO.getId(); //Integer.parseInt(dictDataRespDTO.getValue());

        updateReqVO.setTestWorkstationId(testWorkstationId);
        updateReqVO.setTestWorkstationUserId(SecurityFrameworkUtils.getLoginUserId().intValue());

        if(checkScanWorkstation(id, testWorkstationId)){
            throw new ServiceException(ERROR_STATUS_EXISTS, "该内码和工位已扫描，请勿重复操作!");
        }


        isNextWorkstation(internalCodeDO.getId(), testWorkstationId);

        LocalDateTime now = LocalDateTime.now();
        updateReqVO.setBalanceTime(now);
        updateBalance(updateReqVO);
        updateReqVO.setRigidityTime(now);
        updateRigidity(updateReqVO);

        productProcessCompletedService.createProductProcessCompleted(internalCodeDO.getId(), testWorkstationId);
    }

    private void validateSubmitDeliveryReceipt(String preDeptName, String orderCode, String internalCode){
        DictDataRespDTO deptDictData = dictDataApi.parseDictData("workstation_dept", preDeptName);
        Integer deptId = Integer.parseInt(deptDictData.getValue());
        QueryWrapper<DeliveryReceiptDetailDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id", orderCode);
        queryWrapper.eq("internal_code", internalCode);
        queryWrapper.eq("out_dept_id", deptId);
        Long count = deliveryReceiptDetailMapper.selectCount(queryWrapper);
        if(count == 0){
            throw exception(new ErrorCode(ERROR_STATUS, preDeptName + "还未提交拨交单!"));
        }
    }

    @Override
    public boolean checkScanWorkstation(String internalCode, Integer workstationId) {

        QueryWrapper<InternalCodeDO> internalCodeDOQueryWrapper = new QueryWrapper<>();
        internalCodeDOQueryWrapper.eq("id", internalCode);
        internalCodeDOQueryWrapper.eq("test_workstation_id", workstationId);
        Long cnt = internalCodeMapper.selectCount(internalCodeDOQueryWrapper);
        if(cnt > 0){
            return true;
        }

        internalCodeDOQueryWrapper = new QueryWrapper<>();
        internalCodeDOQueryWrapper.eq("id", internalCode);
        internalCodeDOQueryWrapper.eq("balance_twice_workstation_id", workstationId);
        cnt = internalCodeMapper.selectCount(internalCodeDOQueryWrapper);
        if(cnt > 0){
            return true;
        }

        QueryWrapper<WeightHistoryDO> weightHistoryDOQueryWrapper = new QueryWrapper<>();
        weightHistoryDOQueryWrapper.eq("internal_code", internalCode);
        weightHistoryDOQueryWrapper.eq("weight_workstation_id", workstationId);
        cnt = weightHistoryMapper.selectCount(weightHistoryDOQueryWrapper);
        if(cnt > 0){
            return true;
        }

        QueryWrapper<ProductionCodeDO> productionCodeDOQueryWrapper = new QueryWrapper<>();
        productionCodeDOQueryWrapper.eq("internal_code", internalCode);
        productionCodeDOQueryWrapper.eq("associated_workstation_id", workstationId);
        cnt = productionCodeMapper.selectCount(productionCodeDOQueryWrapper);
        if(cnt > 0){
            return true;
        }

        return false;
    }

    @Override
    public Set listCacheOrder() {
        Set set = new HashSet();
        List values = stringRedisTemplate.opsForHash().values("CACHE_ORDER_CODE");
        set.addAll(values);
        return set;
    }

    @Override
    public PageResult<InternalCodeWorkstationRespVO> listCurrentWorkstationDetail(InternalCodePageReqVO pageReqVO) {
        Long loginUserId = pageReqVO.getLoginUserId();

        InternalCodeRoleVO internalCodeRoleVO = new InternalCodeRoleVO();
        internalCodeRoleVO.setUserId(loginUserId.toString());

        List<WorkstationDO> workstationDOList = workstationMapper.selectList(WorkstationDO::getUserId, loginUserId);
        WorkstationDO workstationDO = workstationDOList.get(0);
        String workstationName = workstationDO.getWorkstationName();
        internalCodeRoleVO.setWorkstationName(workstationName);


        String orderCode = null;
        Object orderCodeObj = stringRedisTemplate.opsForHash().get("CACHE_ORDER_CODE", String.valueOf(loginUserId));
        if(null != orderCodeObj){
            orderCode = orderCodeObj.toString();
            pageReqVO.setOrderCode(orderCode);
        }

        Page<InternalCodeWorkstationRespVO> pageParam = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        List<InternalCodeWorkstationRespVO> list = internalCodeMapper.listCurrentWorkstationDetail(pageParam, pageReqVO, internalCodeRoleVO);

        PageResult<InternalCodeWorkstationRespVO> pageResult = new PageResult<>(list, pageParam.getTotal());
        return pageResult;
    }


}
